package com.cnwidsom.plugins.type;

import java.util.Map;
import com.cnwidsom.utils.ClassUtils;

import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

/**
 * Servlet类型注入器用于拦截符合Servlet规范的Web容器调用,但是在某些特殊需求下会产生问题,如:
 * tomcat中过滤器先于servlet标准接口调用,因此如果想对过滤器执行进行监控的话,必须使用tomcat注入器
 * 
 * @author Administrator
 *
 */
public class ServletTypeInjector implements TypeInjector {
	private Map<String, String> params;

	public String getName() {
		return "servlet";
	}

	public byte[] inject(ClassLoader loader, CtClass ctClass) {
		try {
			if (ctClass.getName().equalsIgnoreCase("javax.servlet.http.HttpServlet")) {
				CtMethod method = ClassUtils.getMatchMethod(ctClass, "service",
						new String[] { "javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse" });

				String extentions = null;
				if (params.get("extentions") != null)
					extentions = (String) params.get("extentions");
				System.out.println("Injecting " + getName() + "...");
				String old_name = method.getName();
				String new_name = old_name + "$impl";

				CtMethod method_new = CtNewMethod.copy(method, new_name, ctClass, null);
				// 增加新方法
				ctClass.addMethod(method_new);

				StringBuffer codeAppender = new StringBuffer();
				codeAppender.append("{\n");

				codeAppender.append("String addr = $1.getRemoteAddr();\n");
				codeAppender.append("String sessionId = $1.getSession().getId();\n");
				codeAppender.append("javax.servlet.http.Cookie[] cookies = $1.getCookies();\n");
				codeAppender.append("String uri = $1.getRequestURI();\n");
				codeAppender.append("int code = -1;\n");

				if (extentions != null) {
					codeAppender.append("java.util.regex.Pattern p = java.util.regex.Pattern.compile(\"" + extentions + "\");\n");
					codeAppender.append("boolean isMatch = p.matcher(uri).matches();\n");
					codeAppender.append("if(isMatch){\n");
					codeAppender.append("com.cnwidsom.monitor.Token.newToken(uri);\n");
					codeAppender.append("}\n");
				}

				codeAppender.append("java.util.List ex_list = new java.util.ArrayList();\n");
				codeAppender.append("long start = System.currentTimeMillis();\n");
				codeAppender.append("try{\n");
				codeAppender.append(new_name + "($$);");
				codeAppender.append("}catch(javax.servlet.ServletException ex1){\n");
				codeAppender.append("ex_list.add(ex1);\n");
				codeAppender.append("throw ex1;\n");
				codeAppender.append("}catch(java.io.IOException ex2){\n");
				codeAppender.append("ex_list.add(ex2);\n");
				codeAppender.append("throw ex2;\n");
				codeAppender.append("}finally{\n");

				if (extentions != null) {
					codeAppender.append("if(isMatch){\n");
				}
				codeAppender.append("long runTime = System.currentTimeMillis()-start;\n");

				codeAppender.append("java.util.Map http_object = new java.util.HashMap();\n");

				codeAppender.append("java.util.Iterator itor = $2.getHeaderNames().iterator();\n");
				codeAppender.append("while (itor.hasNext()) {\n");
				codeAppender.append("String headerName = itor.next().toString();\n");
				codeAppender.append("http_object.put(headerName, $2.getHeader(headerName));\n");
				codeAppender.append("}\n");

				codeAppender.append("if(com.cnwidsom.utils.ClassUtils.getMethod($2.getClass(), \"getStatus\", null, null, null)!=null){\n");
				codeAppender
						.append("code = Integer.parseInt(com.cnwidsom.utils.ClassUtils.getMethod($2.getClass(), \"getStatus\", null, $2, null).toString());\n");
				codeAppender.append("}\n");

				codeAppender.append("if (code != -1) {\n");
				codeAppender.append("http_object.put(\"HTTP_CODE\", String.valueOf(code));\n");
				codeAppender.append("}\n");

				codeAppender.append("com.cnwidsom.monitor.MonitorItem mi = new com.cnwidsom.monitor.MonitorItem(com.cnwidsom.monitor.Token.getTokenHeader(), \""
						+ method.getLongName() + "\", runTime, ex_list, System.currentTimeMillis(), http_object);\n");
				codeAppender.append("if (code >= 400) {\n");
				codeAppender.append("mi.setHasException(true);\n");
				codeAppender.append("mi.getEx_info().add(\"Exception Response:\" + String.valueOf(code));\n");
				codeAppender.append("}\n");

				codeAppender.append("java.util.Map params = new java.util.HashMap();\n");

				// 记录调用参数

				codeAppender.append("params.put(\"addr\",addr);\n");
				codeAppender.append("params.put(\"sessionId\",sessionId);\n");
				codeAppender.append("params.put(\"cookies\",cookies);\n");

				codeAppender.append("mi.setParameters(params);\n");

				codeAppender.append("com.cnwidsom.monitor.Token.endBackToken(mi);\n");

				codeAppender.append("java.util.List token_list = com.cnwidsom.monitor.Token.releaseToken();\n");
				codeAppender.append("if(token_list!=null&&token_list.size()>0){\n");
				// codeAppender.append("System.out.println($1.getRequestURI());\n");
				codeAppender.append("com.cnwidsom.monitor.MonitorLogWritter.log(token_list);\n");
				codeAppender.append("}\n");
				codeAppender.append("}\n");

				codeAppender.append("}\n");
				codeAppender.append("}");

				method.setBody(codeAppender.toString());

				return ctClass.toBytecode();

			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

	public boolean canInject(String nClassName) {
		return nClassName.equalsIgnoreCase("javax.servlet.http.HttpServlet");
	}

	public void setParameters(Map<String, String> params) {
		this.params = params;
	}

	public void init() {
	}

}
